import UIKit

/* XCode15的Swift版本5.9 */

/* Swift属性和方法 */
class User {
    // 存储属性：通过常量或者变量来存储实例的值
    // 存储属性可以是常量也可以是变量
    // 如果将**结构体**实例赋值给一个**常量**，那么该实例中的存储属性（包括常量和变量存储属性）的值都不能被改变
    var id = 0
    var name = ""
    var password = ""
    var email = ""
    // 延迟存储属性
    // 在存储属性声明前加上lazy
    // 在实例的该属性第一次被调用的时候才会计算初始值
    // 必须为变量，因为常量属性在实例初始化完成后必须有值
    lazy var image = ImageInfo()
    var workingYear = 0
    // 计算属性
    // 计算属性只能为变量
    // 它不直接存储值，而是通过get和set方法来获取和设置值
    var holiday: Int {
        // 没有set时，可以不需要写get，直接写get中的内容
        get {
            var days: Int
            switch workingYear {
            case 0: days = 5
            case 1...5: days = 5 + workingYear
            default: days = 12
            }
            // 计算完成后的值需要return
            return days
        }
        set {
            // 传给set的新值缺省名称是newValue
            // set方法没有返回值
            switch newValue {
            case 5: workingYear = 0
            case 6...11: workingYear = newValue - 5
            default: workingYear = 6
            }
        }
    }
}

struct ImageInfo {
    var name = "default name"
    var path = "default path"
}

var theUser = User()
theUser.id = 18
theUser.name = "sammy"
// lazy的变量是一个可选类型，此处为Optional<ImageInfo>
// 在下一条语句执行之前都为nil
print("the name of image is \(theUser.image.name)")

theUser.workingYear = 3
print("sammy has worked for \(theUser.workingYear) years and he has holiday: \(theUser.holiday) days")

// 属性观察器
// 用来监听属性值的变化，并由此来触发特定的操作
// 每当要改变一个属性值的之前和之后，都会触发属性观察器
// 除了延迟存储属性，所有其他属性都可以增加一个属性观察器，对其值的变化进行监控
// 在进行属性初始化的时候是不会触发任何属性观察器的
class Website {
    var domain: String = ""
    var maxClicks = 10000
    var clicks: Int = 0 {
        // willSet在属性的值被改变前触发或被调用
        // 会将新值作为常量参数传入，缺省名称为newValue，可以自定义
        willSet(newClicks) {
            print("clicks will be set to \(newClicks)")
        }
        // didSet在属性的值被改变后触发或被调用
        // didSet则会将旧值作为参数传入，缺省名称为oldValue，可以自定义
        didSet {
            if clicks > maxClicks {
                print("\(clicks) is too high. Fall back to \(oldValue)")
                clicks = oldValue
            } else {
                print("did set clicks from \(oldValue) to \(clicks)")
            }
        }
    }
    var visitCount = 0
    var visitor = [String]()
    var visitDate = ""
    // 实例方法
    func visiting(visitor: String, visitDate: String){
        visitCount += 1
        // 每个实例都有一个隐式属性self，表示这个实例本身
        // 实例方法中可以通过self来引用实例自己
        self.visitor.append(visitor)
        self.visitDate = visitDate
    }
    // 类型方法
    // 在func前面加上static
    // 类型方式只能通过类型对该方法进行调用
    // 在类型方法中，self指向类型本身
    
    // 下标方法
    // 通过自定义下标的方法实现对实例属性的访问
    // 索引值的类型可以有多种类型
    // 要显式声明传入参数的类型和返回类型
    subscript(index: Int) -> String {
        get {
            return visitor[index]
        }
        // 不写set可以实现只读
        set {
            visitor[index] = newValue
        }
    }
}

let theWebsite = Website()
theWebsite.domain = "www.buaa.edu.cn"
theWebsite.clicks = 100
theWebsite.clicks = 200
theWebsite.clicks = 20000

// 类型属性：属于类型本身，不属于特定的实例
// 存储属性和计算属性与具体的实例相关联
class Visitor {
    var name: String = ""
    var stayTime: Int = 0
    // 类型属性使用关键字static来标识
    static var permission: String = "visitor"
}

let theVisitor = Visitor()
theVisitor.name = "Tom"
theVisitor.stayTime = 5
// 类型属性只能通过类型本身来获取和修改，不能通过实例来访问
print("Current permission is \(Visitor.permission)")
Visitor.permission = "administrator"
print("Now permission is \(Visitor.permission)")

let sina = Website()
sina.visiting(visitor: "Tommy", visitDate: "2023-12-09")
print(sina.visitCount)
print(sina.visitor)
print(sina.visitDate)
print("\(sina[0])")
sina[0] = "Pennie"
print("\(sina[0])")

struct structWebsite{
    var visitCount = 0
    // 可变方法
    // 结构体的方法不能修改属性
    // 要使结构体中的方法能够修改属性值必须要声明其为可变方法
    mutating func visiting() {
        visitCount += 1
    }
}

/* Swift高级运算符 */
// 位运算法
var origin: UInt8 = 0b00001111
var result = origin
origin = 240
result = ~origin

let shift: UInt8 = 0b10101010
result = shift << 1
result = shift << 2
result = shift >> 1
result = shift >> 2

var operatorA: UInt8 = 0b11001100
var operatorB: UInt8 = 0b10101010
result = operatorA & operatorB
result = operatorA | operatorB
result = operatorA ^ operatorB

// 溢出运算符
// 当一个整数的赋值超过了最大限度时会报错
// 使用溢出运算符时不会报错，直接将溢出的部分舍弃
// 溢出运算符有加法、减法、乘法
origin = UInt8.max
origin = UInt8.min
// origin = 266

result = UInt8.max &+ 1
result = UInt8.min &- 1
result = UInt8.max &* 2

/* Swift运算符重载 */
struct Point {
    var x = 0
    var y = 0
}

// 双目运算符重载
func -(a: Point, b: Point) -> Point {
    return Point(x: a.x - b.x, y: a.y - b.y)
}

// 单目运算符重载
// 重载一个前缀或者后缀运算时，要加上prefix或者postfix
prefix func -(point: Point) -> Point {
    return Point(x: -point.x, y: -point.y)
}

// 复合运算符重载
func -=(origin: inout Point, decrement: Point){
    origin.x = origin.x - decrement.x
    origin.y = origin.y - decrement.y
}

// 等价运算符重载
// 实现判断类或者结构体的等价
func ==(point1: Point, point2: Point) -> Bool{
    return (point.x == point.x) && (point1.y == point2.y)
}

let a = Point(x: 3, y: 5)
let b = Point(x: 1, y: 6)
// 重载的双目运算符
let c = a - b

let point = Point(x: 3, y: 4)
// 重载的单目运算符
let pointN = -point

var originPoint = Point(x: 3, y: 6)
let decrementPoint = Point (x: 2, y: 8)
// 重载的复合运算符
originPoint -= decrementPoint

let point1 = Point (x: 1, y: 2)
let point2 = Point (x: 2, y: 3)
let point3 = Point (x: 1, y: 2)
// 重载的等价运算符
if point1 == point2 {
    print("pointl is equal to point2")
}
if point1 == point3 {
    print("pointl is equal to point3")
}
